package self.cloud.domain.aliyun.handler;

import com.aliyuncs.IAcsClient;
import com.aliyuncs.alidns.model.v20150109.*;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import self.cloud.domain.aliyun.entity.AliyunDomainRecord;
import self.cloud.domain.core.entity.Domain;

import java.util.ArrayList;
import java.util.List;

@Component
public class AliyunDomainRecordHandler {
    private static final Logger logger = LoggerFactory.getLogger(AliyunDomainRecordHandler.class);

    @Autowired
    IAcsClient acsDomainClient;

    @Autowired
    DescribeDomainRecordsRequest domainRecordsRequest;

    public List<AliyunDomainRecord> findAll(Domain domain) {
        logger.debug("method findAll [domain]:{}", domain.getName());
        List<AliyunDomainRecord> aliyunDomainRecords = new ArrayList<>();

        DescribeDomainRecordsResponse response;

        try {
            this.domainRecordsRequest.setDomainName(domain.getName());

            response = this.acsDomainClient.getAcsResponse(this.domainRecordsRequest);

            for (DescribeDomainRecordsResponse.Record record : response.getDomainRecords()) {
                aliyunDomainRecords.add(new AliyunDomainRecord(record));
            }
        } catch (ClientException e) {
            logger.error(e.toString(), e);
        }

        return aliyunDomainRecords;
    }

    public AliyunDomainRecord findByRR(Domain domain, String rR) {
        logger.debug("method findByRR [domain]:{} [RR]:{}", domain.getName(), rR);
        AliyunDomainRecord result = null;

        List<AliyunDomainRecord> records = this.findAll(domain);
        logger.debug("[domain]:{} [records.count]:{}", domain.getName(), records.size());

        for (AliyunDomainRecord record : records) {
            logger.debug("[record]:{}.{}", record.getRR(), domain.getName());
            if (record.getRR().equals(rR)) {
                result = record;
                break;
            }
        }

        return result;
    }

    @Autowired
    DescribeDomainRecordInfoRequest describeDomainRecordInfoRequest;

    public AliyunDomainRecord findById(String recordId) {
        logger.debug("method findById [RecordId]:{}", recordId);
        AliyunDomainRecord record;

        DescribeDomainRecordInfoResponse response;
        try {
            this.describeDomainRecordInfoRequest.setRecordId(recordId);

            response = this.acsDomainClient.getAcsResponse(this.describeDomainRecordInfoRequest);

            record = new AliyunDomainRecord();
            record.setId(response.getDomainId());
            record.setRR(response.getRR());
            record.setType(response.getType());
            record.setValue(response.getValue());

            return record;
        } catch (ClientException e) {
            logger.error(e.toString(), e);
        }

        return null;
    }

    @Autowired
    AddDomainRecordRequest addDomainRecordRequest;

    @Autowired
    UpdateDomainRecordRequest updateDomainRecordRequest;

    public AliyunDomainRecord save(AliyunDomainRecord aliyunDomainRecord) throws ClientException {
        logger.debug("method save [domainRecord]:{}", aliyunDomainRecord.getId());
        String recordId = null;

        if (aliyunDomainRecord.getId() == null || aliyunDomainRecord.getId().equals("")) {
            logger.debug("recordId is null or empty, create new one");
            AddDomainRecordResponse response;

            try {
                this.addDomainRecordRequest.setRR(aliyunDomainRecord.getRR());
                this.addDomainRecordRequest.setType(aliyunDomainRecord.getType());
                this.addDomainRecordRequest.setValue(aliyunDomainRecord.getValue());

                response = this.acsDomainClient.getAcsResponse(this.addDomainRecordRequest);

                recordId = response.getRecordId();
            } catch (ServerException e) {
                logger.error(e.toString(), e);
            } catch (ClientException e) {
                logger.error(e.toString(), e);
            }

        } else {
            logger.debug("recordId is not null or empty, update entity");
            UpdateDomainRecordResponse response;

            try {
                this.updateDomainRecordRequest.setRecordId(aliyunDomainRecord.getId());
                this.updateDomainRecordRequest.setRR(aliyunDomainRecord.getRR());
                this.updateDomainRecordRequest.setType(aliyunDomainRecord.getType());
                this.updateDomainRecordRequest.setValue(aliyunDomainRecord.getValue());

                response = this.acsDomainClient.getAcsResponse(this.updateDomainRecordRequest);

                recordId = response.getRecordId();

            } catch (ClientException e) {
                if(e.getErrMsg().equals("The DNS record already exists.")) {
                    throw e;
                }
                logger.error(e.getErrMsg());
            }
        }

        if(recordId == null || recordId.equals("")) {
            throw new NullPointerException("Cannot save record");
        }

        return this.findById(recordId);
    }
}
